//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "EIC.h"
#include "MTAG_CtrlStd.h"
#include "CSpeedBtn.h"

#define MODULE_TAG MTAG_CSPEEDBTN

//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
static inline void ValidCtrCheck(CSpeedButton *)
{
  new CSpeedButton(NULL);
}
//---------------------------------------------------------------------------
extern "C" const BitBtnOption BitBtnOptions[NB_KIND];

namespace Cspeedbtn
{
  void __fastcall PACKAGE Register()
  {
    TComponentClass classes[1] = {__classid(CSpeedButton)};
    RegisterComponents("EIC Ctrlstd", classes, 0);
  }
}
//---------------------------------------------------------------------------
__fastcall CSpeedButton::CSpeedButton(TComponent* Owner) : TSpeedButton(Owner)
{
  TSpeedButton::Glyph = NULL;
  FKind = Cbitbtn::bkCustom;
//  GlyphInactif = new Graphics::TBitmap;
}

__fastcall CSpeedButton::~CSpeedButton()
{
//  delete GlyphInactif;   GlyphInactif = NULL;
}
//---------------------------------------------------------------------------
void __fastcall CSpeedButton::SetKind(CBitBtnKind Value)
{
  if (Value != FKind )
  {
    if (Value != Cbitbtn::bkCustom)
       {
       TSpeedButton::Glyph->LoadFromResourceName((int)HInstance, BitBtnOptions[Value].Name);
//       SetGlyphInactif(TSpeedButton::Glyph);
       }
    FKind = Value;
    Invalidate();
  }
}
//---------------------------------------------------------------------------
void __fastcall CSpeedButton::SetGlyph(Graphics::TBitmap* Value)
{
#ifdef _DEBUG
    if (Value != Cbitbtn::bkCustom)
        ShowMessage("Composant : " + Name + "\nVous ne devez pas affecter la propriété Glyph lorsque Kind est différente de bkCustom");
#endif
    TSpeedButton::Glyph = Value;
//    SetGlyphInactif(TSpeedButton::Glyph);
}
//---------------------------------------------------------------------------
void __fastcall CSpeedButton::CNDrawItem(TMessage& Msg)
{
TOwnerDrawState state;
TPoint  GlyphPos(0,0);
TRect Result;
long BiDiFlags;
  try
  {
    if (_WINPLATFORM == VP_WINDOWS_95_98) //Sous 98, lorsqu'un écran contenant de nombreux boutons inactifs est dessiné (à la méthode EIC), certains apparaissaient hors de l'écran
       TSpeedButton::Dispatch(&Msg);
    else
       {
       // si le bouton est enfoncé
       if (FState == bsDown)
         state = state << odSelected;

       // si le bouton est désactivé
       if (FState == bsDisabled || !Enabled)
         state = state << odDisabled;

       // dessine le bouton
       DoDrawButtonFace(Canvas,
                        ClientRect,
                        Flat,
                        Transparent,
                        FState,
                        MouseInControl,
                        Color,
                        false,
                        state,
                        Down);
      CalcButtonLayout(Canvas, ClientRect, Caption, Layout, Margin, Spacing, &GlyphPos, &Result);

       // dessine le Glyph
       DoDrawButtonGlyph(Canvas,
                         ClientRect,
                         Color,
                         Caption,
                         FKind,
                         Glyph,
                         Margin,
                         Spacing,
                         state,
                         GlyphPos);

       // écrit le texte
       DoDrawButtonText(Canvas,
//                        ClientRect,
                        Result,
                        Color,
                        Font->Color,
                        Caption,
                        FKind,
                        Glyph,
                        Margin,
                        Spacing,
                        state,
                        GlyphPos);
       }
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(60), e);
   }
  // message traité
  Msg.Result = TRUE;
}

void __fastcall CSpeedButton::CalcButtonLayout(TCanvas *Canvas, const TRect &Client,
                                                const AnsiString &Caption,
                                                TButtonLayout Layout,
                                                int Margin,
                                                int Spacing,
                                                TPoint *GlyphPos,
                                                TRect *TextBounds)
{
TPoint  TextPos ;
TPoint  ClientSize, GlyphSize, TextSize ;
TPoint  TotalSize ;
int BiDiFlags = DrawTextBiDiModeFlags(0);
  if (BiDiFlags & DT_RIGHT)
  {
    if (Layout == blGlyphLeft)
      Layout = blGlyphRight;
    else if (Layout == blGlyphRight)
      Layout = blGlyphLeft;
  }
  // calculate the item sizes
  ClientSize = Point(Client.Right - Client.Left, Client.Bottom - Client.Top);
  if (Glyph != NULL)
    GlyphSize = Point(Glyph->Width / NumGlyphs, Glyph->Height);
  else
    GlyphSize = Point(0, 0);
  if (!Caption.IsEmpty())
  {
    *TextBounds = Rect(0, 0, Client.Right - Client.Left, 0);
    DrawText(Canvas->Handle, Caption.c_str(), Caption.Length(), TextBounds, DT_CALCRECT | BiDiFlags);
    TextSize = Point(TextBounds->Right - TextBounds->Left, TextBounds->Bottom - TextBounds->Top);
  }
  else
  {
    *TextBounds = Rect(0, 0, 0, 0);
    TextSize = Point(0,0);
  }
  // If the layout has the glyph on the right or the left, then both the
  //  text and the glyph are centered vertically.  If the glyph is on the top
  //  or the bottom, then both the text and the glyph are centered horizontally.
  if (Layout == blGlyphLeft || Layout == blGlyphRight)
  {
    GlyphPos->y = (ClientSize.y - GlyphSize.y + 1) / 2;
    TextPos.y = (ClientSize.y - TextSize.y + 1) / 2;
  }
  else
  {
    GlyphPos->x = (ClientSize.x - GlyphSize.x + 1) / 2;
    TextPos.x = (ClientSize.x- TextSize.x + 1) / 2;
  }
  //if there is no text or no bitmap, then Spacing is irrelevant
  if ((TextSize.x == 0) || (GlyphSize.x == 0) )
    Spacing = 0;
  // adjust Margin and Spacing
  if (Margin == -1)
  {
    if (Spacing == -1)
    {
      TotalSize = Point(GlyphSize.x + TextSize.x, GlyphSize.y + TextSize.y);
      if (Layout==blGlyphLeft ||  Layout==blGlyphRight)
        Margin = (ClientSize.x - TotalSize.x) / 3;
      else
        Margin = (ClientSize.y - TotalSize.y) / 3;
      Spacing = Margin;
    }
    else
    {
      TotalSize = Point(GlyphSize.x + Spacing + TextSize.x, GlyphSize.y + Spacing + TextSize.y);
      if (Layout==blGlyphLeft || Layout== blGlyphRight)
        Margin = (ClientSize.x - TotalSize.x + 1) / 2;
      else
        Margin = (ClientSize.y - TotalSize.y + 1) / 2;
    }
  }
  else
  {
    if (Spacing == -1)
    {
      TotalSize = Point(ClientSize.x - (Margin + GlyphSize.x), ClientSize.y - (Margin + GlyphSize.y));
      if (Layout==blGlyphLeft || Layout== blGlyphRight)
        Spacing = (TotalSize.x - TextSize.x) / 2;
      else
        Spacing = (TotalSize.y - TextSize.y) / 2;
    }
  }
  switch (Layout)
  {
    case blGlyphLeft:
      GlyphPos->x = Margin;
      TextPos.x = GlyphPos->x + GlyphSize.x + Spacing;
      break;
    case blGlyphRight:
      GlyphPos->x = ClientSize.x - Margin - GlyphSize.x;
      TextPos.x = GlyphPos->x - Spacing - TextSize.x;
      break;
    case blGlyphTop:
        GlyphPos->y = Margin;
        TextPos.y = GlyphPos->y + GlyphSize.y + Spacing;
      break;
    case blGlyphBottom:
        GlyphPos->y = ClientSize.y - Margin - GlyphSize.y;
        TextPos.y = GlyphPos->y - Spacing - TextSize.y;
        break;
  }
  // fixup the result variables
  GlyphPos->x += Client.Left ;
  GlyphPos->y += Client.Top ;
  OffsetRect(TextBounds, TextPos.x + Client.Left ,TextPos.y + Client.Top );
}
//---------------------------------------------------------------------------
void __fastcall CSpeedButton::DoDrawButtonGlyph(TCanvas* Canvas,
                                  const TRect &ClientRect,
                                  TColor Color,
                                  const AnsiString &aCaption,
                                  CBitBtnKind Kind,
                                  Graphics::TBitmap *Glyph,
                                  int Margin,
                                  int Spacing,
                                  const TOwnerDrawState& state,
                                  const TPoint &LePoint)
{
  Graphics::TBitmap* LeGlyph = NULL;
  TPoint PGlyph;
  TRect RectDest;

  if (!Glyph->Empty)
     {
     LeGlyph = new Graphics::TBitmap;
     LeGlyph->Assign(Glyph);
     PGlyph = LePoint;
     RectDest.left   = PGlyph.x;
     RectDest.top    = PGlyph.y;
     RectDest.right  = min(PGlyph.x + LeGlyph->Width, (long)ClientRect.Right - ClientRect.Left - GetSystemMetrics(SM_CXEDGE));
     RectDest.bottom = min(PGlyph.y + LeGlyph->Height, (long)ClientRect.Bottom - ClientRect.Top - GetSystemMetrics(SM_CYEDGE));

     // Dessine le Glyph inactif
     if (state.Contains(odDisabled))
       {
       Graphics::TBitmap *MaskBitmap = NULL;
       MaskBitmap = new Graphics::TBitmap;
       MaskBitmap->Monochrome = true;
       MaskBitmap->Width = LeGlyph->Width;
       MaskBitmap->Height = LeGlyph->Height;
       // Génère un mask noir qui exclue le fond et les pixels blancs
       SetBkColor(LeGlyph->Canvas->Handle, LeGlyph->TransparentColor);
       BitBlt(MaskBitmap->Canvas->Handle, 0, 0, LeGlyph->Width, LeGlyph->Height, LeGlyph->Canvas->Handle, 0, 0, SRCCOPY);
       SetBkColor(LeGlyph->Canvas->Handle, RGB(0xff, 0xff, 0xff));
       BitBlt(MaskBitmap->Canvas->Handle, 0, 0, LeGlyph->Width, LeGlyph->Height, LeGlyph->Canvas->Handle, 0, 0, NOTSRCERASE);

       // draw the new mask 'etched' to hdc
       SetBkColor(Canvas->Handle, RGB(255, 255, 255));
       SelectObject(Canvas->Handle, GetSysColorBrush(COLOR_3DHILIGHT));
       // E20746 op code is (Dst ^ (Src & (Pat ^ Dst))) => Dessine la zone claire, puis la zone sombre
       BitBlt(Canvas->Handle, PGlyph.x + 1, PGlyph.y + 1, LeGlyph->Width, LeGlyph->Height, MaskBitmap->Canvas->Handle, 0, 0, 0xE20746);
       SelectObject(Canvas->Handle, GetSysColorBrush(COLOR_3DSHADOW));
       BitBlt(Canvas->Handle, PGlyph.x, PGlyph.y, LeGlyph->Width, LeGlyph->Height, MaskBitmap->Canvas->Handle, 0, 0, 0xE20746);

       delete MaskBitmap;
       }
     else
       {
       Canvas->Brush->Color = Color;
       Canvas->BrushCopy(RectDest,
                         LeGlyph,
                         LeGlyph->Canvas->ClipRect,
                         LeGlyph->TransparentColor);
       }
     }

delete LeGlyph;
}
//---------------------------------------------------------------------------
void __fastcall CSpeedButton::DoDrawButtonText(TCanvas* Canvas,
                                 const TRect &ClientRect,
                                 TColor Color,
                                 TColor FontColor,
                                 const AnsiString &aCaption,
                                 CBitBtnKind Kind,
                                 Graphics::TBitmap *Glyph,
                                 int Margin,
                                 int Spacing,
                                 const TOwnerDrawState& state,
                                 const TPoint &LePoint)
{
  if (aCaption.Length() == 0)
    return;

  TRect RText = ClientRect;
  SetBkMode(Canvas->Handle, TRANSPARENT);

  // si le bouton est enfoncé
  if (state.Contains(odSelected))
  {
    // décale le texte
    OffsetRect(&RText, 1, 1);
  }

  // si le bouton est désactivé
  if (state.Contains(odDisabled))
    {
    //Cas où le bouton a des couleurs standards
    // => On dessine l'ombre du texte
    if (Color == clBtnFace && FontColor == clWindowText)
       {
       OffsetRect(&RText, 1, 1);
       Canvas->Font->Color = GetColorHi(Color, 0x40);
       DrawText(Canvas->Handle, aCaption.c_str(), -1, &RText, DT_VCENTER | DT_SINGLELINE);
       OffsetRect(&RText, -1, -1);
       }

    //On atténue la couleur du texte
    // => elle doit se rapprocher de la couleur du fond
    Canvas->Font->Color = (TColor)RGB(1/3. * GetRValue(ColorToRGB(FontColor)) + 2/3. * GetRValue(ColorToRGB(Color)),
                                      1/3. * GetGValue(ColorToRGB(FontColor)) + 2/3. * GetGValue(ColorToRGB(Color)),
                                      1/3. * GetRValue(ColorToRGB(FontColor)) + 2/3. * GetRValue(ColorToRGB(Color)));
    }
  else
    SetTextColor(Canvas->Handle, ColorToRGB(FontColor));

  // Ecriture du texte
  DrawText(Canvas->Handle, aCaption.c_str(), -1, &RText, DT_VCENTER | DT_SINGLELINE);

  // si le bouton a le focus
  if (state.Contains(odFocused))
  {
    // dessine le rectangle de sélection
    TRect RFocus = ClientRect;
    InflateRect(reinterpret_cast<PRECT>(&RFocus),-4, -4);
    Canvas->DrawFocusRect(RFocus);
  }
}
//---------------------------------------------------------------------------

